#include "Terrain.h"

Terrain::Terrain(dSpaceID space, std::vector<int> &heights, int depth, int width,
				 float xScale, float yScale, float zScale,
				 float xTranslation, float yTranslation, float zTranslation,
				 bool center) : useTexture(false)
{
	int i, j, count, stepSize;

	// Center the terrain around (0,0,0) with respect to x and z
	if(center)
	{
		xTranslation -= width * xScale * 0.5f;
		zTranslation -= depth * zScale * 0.5f;
	}

	std::cout << "Building vertex data (" << width * depth << " verts):";
	stepSize = (int)(depth / 88);
	for(i = 0, count = 0; i < depth; ++i, ++count)
	{
		for(j = 0; j < width; ++j)
		{
			Vertex vert;
			vert.position = cml::vector3f(j * xScale + xTranslation,
										  heights.at(i * width + j) * yScale + yTranslation,
										  i * zScale + zTranslation);
			//vert.normal = cml::vector3f(0.0f, 1.0f, 0.0f);
			vert.color = cml::vector3f(1.0f, 1.0f, 1.0f);
			vertices.push_back(vert);	
		}
		if(count > stepSize)
		{
			count = 0;
			std::cout << ".";
		}
	}
	std::cout << "done!\n";

	std::cout << "Building index data (" << (width - 1) * (depth - 1) * 6 << " verts):";
	stepSize = (int)(depth / 88);
	for(i = 0, count = 0; i < depth - 1; ++i, ++count)
	{
		for(j = 0; j < width - 1; ++j)
		{
			indices.push_back(i * (width) + j); 
			indices.push_back((i + 1) * (width) + j);
			indices.push_back(i * (width) + j + 1);

			indices.push_back((i + 1) * (width) + j);
			indices.push_back((i + 1) * (width) + j + 1);
			indices.push_back(i * (width) + j + 1);
		}
		if(count > stepSize)
		{
			count = 0;
			std::cout << ".";
		}
	}
	std::cout << "done!\n";

	//Normalize normals
	cml::vector3f oneTwoVect;
	cml::vector3f oneThreeVect;

	cml::vector3f twoOneVect;
	cml::vector3f twoThreeVect;

	cml::vector3f threeOneVect;
	cml::vector3f threeTwoVect;

	for(i = 0; i < vertices.size(); ++i)
		vertices.at(i).normal = cml::vector3f(0.0f, 0.0f, 0.0f); //make sure normals are zeroed


	std::cout << "Finding terrain normals: ";
	stepSize = (int)(indices.size() / 88);
	for(i = 0, count = 0; i < indices.size(); i += 3, count += 3)
	{
		oneTwoVect = vertices.at(indices.at(i + 1)).position - vertices.at(indices.at(i)).position;
		oneThreeVect = vertices.at(indices.at(i + 2)).position - vertices.at(indices.at(i)).position;
		vertices.at(indices.at(i)).normal += cml::cross(oneTwoVect, oneThreeVect);

		twoOneVect = vertices.at(indices.at(i)).position - vertices.at(indices.at(i + 1)).position;
		twoThreeVect = vertices.at(indices.at(i + 2)).position - vertices.at(indices.at(i + 1)).position;
		vertices.at(indices.at(i + 1)).normal += cml::cross(twoThreeVect, twoOneVect);

		threeOneVect = vertices.at(indices.at(i)).position - vertices.at(indices.at(i + 2)).position;
		threeTwoVect = vertices.at(indices.at(i + 1)).position - vertices.at(indices.at(i + 2)).position;
		vertices.at(indices.at(i + 2)).normal += cml::cross(threeOneVect, threeTwoVect);

		if(count > stepSize)
		{
			count = 0;
			std::cout << ".";
		}
	}
	std::cout << "done!\n";

	for(i = 0; i < vertices.size(); ++i)
		vertices.at(i).normal.normalize();
	//Done normalizing

	std::cout << "ODE is creating the trimesh for the terrain...";
	dGeomTriMeshDataBuildSingle(data, (dReal*)&vertices[0].position[0], sizeof(Vertex),
								width * depth, (dTriIndex*)&indices[0],
								(width - 1) * (depth - 1) * 2 * 3, sizeof(GLuint) * 3);
	std::cout << "done\n";

	dGeomID terrainWorldMesh = dCreateTriMesh(space, data, 0, 0, 0);

	texture = SOIL_load_OGL_texture("CheckerBoard.bmp", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS);
}

void Terrain::render()
{
	glColor3ubv(color);

	GLfloat mat_specular[] = {0.1f, 0.1f, 0.1f};
	glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);

	if(useTexture)
		glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, texture);
	bool firstTriangleOfQuad = true;
	for(int i = 0; i < indices.size(); ++i)
	{
		if(firstTriangleOfQuad)
		{
			glBegin(GL_TRIANGLES);
			glTexCoord2f(0.0f, 0.0f);
			glNormal3fv(vertices.at(indices.at(i)).normal.data());
			glVertex3fv(vertices.at(indices.at(i)).position.data());
			glTexCoord2f(0.0f, 1.0f);
			glNormal3fv(vertices.at(indices.at(++i)).normal.data()); //Incr i
			glVertex3fv(vertices.at(indices.at(i)).position.data());
			glTexCoord2f(1.0f, 0.0f);
			glNormal3fv(vertices.at(indices.at(++i)).normal.data()); //Incr i
			glVertex3fv(vertices.at(indices.at(i)).position.data());
			glEnd(); // GL_TRIANGLES
		}
		else
		{
			glBegin(GL_TRIANGLES);
			glTexCoord2f(0.0f, 1.0f);
			glNormal3fv(vertices.at(indices.at(i)).normal.data());
			glVertex3fv(vertices.at(indices.at(i)).position.data());
			glTexCoord2f(1.0f, 1.0f);
			glNormal3fv(vertices.at(indices.at(++i)).normal.data()); //Incr i
			glVertex3fv(vertices.at(indices.at(i)).position.data());
			glTexCoord2f(1.0f, 0.0f);
			glNormal3fv(vertices.at(indices.at(++i)).normal.data()); //Incr i
			glVertex3fv(vertices.at(indices.at(i)).position.data());
			glEnd(); // GL_TRIANGLES
		}
		firstTriangleOfQuad = !firstTriangleOfQuad;
	}
	glDisable(GL_TEXTURE_2D);
}